/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  SpiSlave_Mld.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL SpiSlave_Slave plugins.
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "Std_Types.h"
#include "SpiSlave_Mld.h"
#include "SpiSlave_Ip.h"
#include "SpiSlave_Cfg.h"
#include "SpiSlave_Fault.h"
#define SPI_SLV_START_SEC_CODE
#include "SpiSlave_MemMap.h"

/* Compatible with older configurations */
#ifndef SPI_SLV_MAX_RETRY_TIMES
#define SPI_SLV_MAX_RETRY_TIMES 20U
#endif
/*PRQA S 4399,2895 EOF*/
/**
 * @description:
 * @param {mld_spi_slv_device} *dev
 * @param {void*} priv
 * @return {*}
 */
void mld_spi_slv_dev_init(struct mld_spi_slv_device *dev, \
                                     void *priv)
{
    dev->priv = priv;
}
/**
 * @description:
 * @param {mld_spi_slv_device} *dev
 * @param {mld_spi_slv_module*} bus
 * @param {void*} priv
 * @return {*}
 */
void mld_spi_slv_dev_attach_bus(struct mld_spi_slv_device *dev, \
        struct mld_spi_slv_module *bus)
{
    dev->bus = bus;
    bus->bus_ops->spi_slv_set_predev_config(bus, dev);
}
/**
 * @description:
 * @param {mld_spi_slv_module} *bus
 * @param {void} *bus_priv
 * @param {void*} dev_mode
 * @return {*}
 */
void mld_spi_slv_bus_set_privdata(struct mld_spi_slv_module *bus, \
        void *bus_priv, void *dev_mode)
{
    bus->priv = bus_priv;
    bus->dev_mode = dev_mode;
}
/**
 * @description:
 * @param {mld_spi_slv_module} *bus
 * @param {uint32} base
 * @param {mld_spi_slv_ops*} ops
 * @return {*}
 */
void mld_spi_slv_bus_create(struct mld_spi_slv_module *bus, \
                                      uint32 base, const struct mld_spi_slv_ops *ops)
{
    bus->base = base;
    bus->bus_ops = ops;
}
void sync_finished_callback(struct mld_spi_slv_module *bus)
{
    /*PRQA S 2895 1*/
    bus->state &= (uint32)(~SPI_SLV_BUS_BUSY_SYNC_MASK);
}

void next_async_item_cb(struct mld_spi_slv_async *src, \
                                      struct mld_spi_slv_async *dst)
{
    dst->len = src->len;
    dst->prxdata.val = src->prxdata.val;
    dst->ptxdata.val = src->ptxdata.val;
    dst->width_type = src->width_type;
    dst->cur_remian = dst->len;
    dst->rx_cur = 0;
    dst->tx_cur = 0;
}
/**
 * @brief Checks if the SPI slave operation function pointers are non-NULL.
 *
 * Validates that all the function pointers in the SPI slave operations structure are
 * non-NULL. If any function pointer is NULL, FALSE is returned.
 *
 * @param ops Pointer to the SPI slave operations structure.
 *
 * @return TRUE if all function pointers are non-NULL, FALSE otherwise.
 */
static boolean check_the_ops(const struct mld_spi_slv_ops *ops)
{
    boolean ret = TRUE;
    SpiSLvFaultInj_SpiSLv_OpsChk_Err();
    if(NULL_PTR == ops->spi_slv_init)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_deinit)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_write_data)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_read_data)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_can_write)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_can_read)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_setup_irq_mask)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_clr_irq_state)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_set_predev_config)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_vector_transmit_receive)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_vector_transmit_receive_irq)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_vector_transmit_receive_dma)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_irq_state)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_dma_stop)
        ret = FALSE;
    if(NULL_PTR == ops->spi_slv_transmit_stop)
        ret = FALSE;
    return ret;
}
/**
 * @brief Initializes the SPI slave module.
 *
 * Initializes the SPI slave module and sets up relevant parameters.
 *
 * @param bus Pointer to the SPI slave module structure.
 *
 * @return Returns 0 on successful initialization, otherwise returns an error code.
 */
sint32 mld_spi_slv_init(struct mld_spi_slv_module *bus)
{
    sint32 ret = 0;
    SpiSLvFaultInj_SpiSLv_BusChk_Err();
    if (bus && bus->bus_ops && check_the_ops(bus->bus_ops)) {
        bus->state = 0;
        ret = bus->bus_ops->spi_slv_init(bus);

        if (!ret) {
            bus->state |= SPI_SLV_STATE_INITED;
        } else {
            SPI_SLV_DBG("%s error: %d\n", __FUNCTION__, ret);
            ret = -SLV_ERR_LOW_LEVEL;
        }
    } else {
        SPI_SLV_DBG("%s error no bus or ops \n", __FUNCTION__);
        ret = -SLV_ERR_NO_BUS;
    }

    return ret;
}
/**
 * @brief De-initializes the SPI slave module.
 *
 * This function is responsible for de-initializing the SPI slave module by calling
 * the de-initialization function pointer provided in the bus operations structure.
 * It also resets the state of the SPI slave module to indicate that it is no longer
 * initialized.
 *
 * @param[in,out] bus Pointer to the SPI slave module structure. This structure
 *                    contains the necessary information and function pointers to
 *                    operate the SPI slave bus.
 *
 * @return sint32 Returns 0 on success, indicating that the SPI slave module has been
 *               successfully de-initialized. On failure, it returns a negative error
 *               code indicating the reason for failure. Specifically, it returns
 *               -SLV_ERR_NO_BUS if the provided bus pointer or its bus operations
 *               structure is NULL.
 */
sint32 mld_spi_slv_deinit(struct mld_spi_slv_module *bus)
{
    sint32 ret = 0;
    SpiSLvFaultInj_SpiSLv_BusChk_Err();
    if (bus && bus->bus_ops){
        bus->state = 0;
        ret = bus->bus_ops->spi_slv_deinit(bus);
    } else {
        SPI_SLV_DBG("%s error no bus or ops \n", __FUNCTION__);
        ret = -SLV_ERR_NO_BUS;
    }

    return ret;
}
#define SPI_SLV_STOP_SEC_CODE
#include "SpiSlave_MemMap.h"

#define SPI_SLV_START_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"
/**
 * @brief Stops SPI slave module operations.
 *
 * This function stops all ongoing SPI slave operations, including DMA transfers and
 * transmit activities. It does so by calling the corresponding stop functions provided
 * by the bus operations structure. If the SPI slave module or its bus operations are
 * not valid, the function does nothing.
 *
 * Note that the state of the SPI slave module is reset to the initialized state after
 * stopping the operations, but only if the module was previously in the initialized
 * state.
 *
 * @param[in,out] bus Pointer to the SPI slave module structure. This structure should
 *                    contain the necessary information and pointers to the bus
 *                    operations that are required to stop the SPI slave operations.
 */
void mld_spi_slv_stop(struct mld_spi_slv_module *bus)
{
    if (bus && bus->bus_ops) {
        if (bus->state & SPI_SLV_STATE_INITED) {
            bus->bus_ops->spi_slv_dma_stop(bus);
            bus->bus_ops->spi_slv_transmit_stop(bus);
            /*PRQA S 4424 1*/
            bus->state = SPI_SLV_STATE_INITED;
        }
    }
}
/**
 * @brief Performs a vector-based transmit and receive operation on the SPI slave module.
 *
 * This function initiates a SPI transmission and reception operation using a vector
 * structure to define the transmit and receive buffers. It handles both transmit and
 * receive operations simultaneously, if requested. The function checks the SPI slave
 * module's state and bus operations before proceeding.
 *
 * @param[in,out] bus Pointer to the SPI slave module structure. This structure must
 *                    contain valid bus operations and be in the initialized state.
 * @param[in] dev Pointer to the SPI slave device structure. This structure provides
 *                device-specific configuration and parameters for the operation.
 * @param[in,out] vector Pointer to the SPI slave asynchronous vector structure. This
 *                       structure defines the transmit and receive buffers, as well
 *                       as other operation parameters.
 *
 * @return Returns 0 on success, or a negative error code on failure. Possible error
 *         codes include:
 *         - SLV_ERR_NO_BUS: The SPI slave module or its bus operations are not valid.
 *         - SLV_ERR_NO_INIT: The SPI slave module is not initialized.
 *         - SLV_ERR_BUSY: The SPI slave module is already busy.
 *         - SLV_ERR_LOW_LEVEL: A low-level error occurred during the SPI operation.
 */
sint32 mld_spi_slv_vector_transmit_receive(struct mld_spi_slv_module *bus,
                                       struct mld_spi_slv_device *dev,
                                       struct mld_spi_slv_async *vector)
{

    sint32 ret = 0;

    SpiSLvFaultInj_SpiSLv_BusChk_Err();
    if (!bus || !bus->bus_ops) {
        ret = -SLV_ERR_NO_BUS;
    } else if (bus->state & SPI_SLV_STATE_INITED) {
        /* busy inj */
        SpiSLvFaultInj_SpiSLv_BusyChk_Err();
        if (!(bus->state & SPI_SLV_BUS_BUSY_MASK)) {
            /* async mode will check and clean it */
            if (vector->ptxdata.val)
                bus->state |= SPI_SLV_STATE_BUSY_TX;

            if (vector->prxdata.val)
                bus->state |= SPI_SLV_STATE_BUSY_RX;

            vector->expect_len =  0;
            ret = bus->bus_ops->spi_slv_vector_transmit_receive(bus, dev,vector,0);


            if (ret < 0) {
                SPI_SLV_DBG("%s error: %d\n", __FUNCTION__, ret);
                bus->state &= (uint32)(~(SPI_SLV_BUS_BUSY_MASK | SPI_SLV_BUS_BUSY_IRQ_MASK | SPI_SLV_STATE_EXT_FLAGS));
                /* reset bus avoid affecting the next transmission */
                bus->bus_ops->spi_slv_transmit_stop(bus);
                ret = -SLV_ERR_LOW_LEVEL;
            }

            sync_finished_callback(bus);
        } else {
            SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_BUSY);
            ret = -SLV_ERR_BUSY;
        }
        SpiSLvFaultInj_SpiSLv_BusyChk_Err_end();
    } else {
        SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_NO_INIT);
        ret = -SLV_ERR_NO_INIT;
    }

    return ret;
}
/**
 * @brief Transmits and receives SPI data vectors using interrupts.
 *
 * This function initiates the transmission and reception of SPI data vectors using
 * interrupts. It prepares the SPI bus and device for the operation, checks if the bus
 * is not busy, and then initiates the transfer. If the transfer fails, it cleans up
 * the bus state and stops any ongoing transmission.
 *
 * @param bus Pointer to the SPI slave module structure. This structure contains
 *            all the necessary information and functions to operate the SPI bus.
 * @param dev Pointer to the SPI slave device structure. This structure contains
 *            device-specific information and configuration for the SPI transfer.
 * @param vector Pointer to the SPI asynchronous transfer vector structure. This
 *               structure contains the transmit and receive buffers, as well as
 *               other transfer-related information.
 *
 * @return Returns 0 on success, or a negative error code on failure. The possible
 *         error codes are:
 *         - SLV_ERR_NO_BUS: If the SPI bus structure or its operations are NULL.
 *         - SLV_ERR_NO_INIT: If the SPI bus has not been initialized.
 *         - SLV_ERR_BUSY: If the SPI bus is already busy with another transfer.
 *         - SLV_ERR_LOW_LEVEL: If a low-level error occurs during the transfer.
 */
sint32 mld_spi_slv_vector_transmit_receive_irq(struct mld_spi_slv_module *bus,
        struct mld_spi_slv_device *dev, \
        struct mld_spi_slv_async *vector)
{
    sint32 ret = 0;
    SpiSLvFaultInj_SpiSLv_BusChk_Err();
    if (!bus || !bus->bus_ops) {
        ret = -SLV_ERR_NO_BUS;
    } else if (bus->state & SPI_SLV_STATE_INITED) {
        SpiSLvFaultInj_SpiSLv_BusyChk_Err();
        if (!(bus->state & SPI_SLV_BUS_BUSY_MASK)) {
            if (vector->ptxdata.val)
                bus->state |= SPI_SLV_STATE_BUSY_TX | SPI_SLV_STATE_IRQ_TX;

            if (vector->prxdata.val)
                bus->state |= SPI_SLV_STATE_BUSY_RX | SPI_SLV_STATE_IRQ_RX;

            vector->expect_len =  0;
            ret = bus->bus_ops->spi_slv_vector_transmit_receive_irq(bus, dev, vector);

            if (ret < 0) {
                bus->state &= (uint32)(~(SPI_SLV_BUS_BUSY_MASK | SPI_SLV_BUS_BUSY_IRQ_MASK | SPI_SLV_STATE_EXT_FLAGS));
                bus->bus_ops->spi_slv_transmit_stop(bus);
                SPI_SLV_DBG("%s error: %d\n", __FUNCTION__, ret);
                ret = -SLV_ERR_LOW_LEVEL;
            } else {
                /* async mode will check and clean it */
            }
        } else {
            SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_BUSY);
            ret = -SLV_ERR_BUSY;
        }
        SpiSLvFaultInj_SpiSLv_BusyChk_Err_end();
    } else {
        SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_NO_INIT);
        ret = -SLV_ERR_NO_INIT;
    }

    return ret;
}
/**
 * @brief Transmits and receives SPI data using DMA in asynchronous mode.
 *
 * This function initiates the transmission and reception of SPI data using DMA,
 * allowing for efficient data transfer with minimal CPU intervention. It is intended
 * for use in asynchronous mode, where the transmission and reception are handled
 * independently from the main CPU execution flow.
 *
 * The function first checks if the SPI slave module and its bus operations are valid
 * and if the module is initialized. It then verifies if the bus is not currently
 * busy with another operation. If all conditions are met, it sets the appropriate
 * busy and DMA flags in the module's state, initiates the DMA transfer, and waits
 * for it to complete.
 *
 * If an error occurs during the DMA transfer, the function cleans up the state flags,
 * stops the SPI transmission, and returns an error code.
 *
 * @param[in,out] bus Pointer to the SPI slave module structure. This structure
 *                    contains the necessary information and pointers to the bus
 *                    operations that are required to perform the DMA transfer.
 * @param[in] dev Pointer to the SPI slave device structure. This structure
 *               contains specific device configuration and parameters that may
 *               be required for the DMA transfer.
 * @param[in,out] vector Pointer to the asynchronous transfer vector structure.
 *                       This structure contains the transmit and receive buffers,
 *                       as well as other transfer parameters.
 *
 * @return Returns 0 on success, or a negative error code on failure.
 *         -SLV_ERR_NO_BUS: If the SPI slave module or its bus operations are not valid.
 *         -SLV_ERR_NO_INIT: If the SPI slave module is not initialized.
 *         -SLV_ERR_BUSY: If the SPI bus is already busy with another operation.
 *         -SLV_ERR_LOW_LEVEL: If an error occurs during the DMA transfer.
 */
sint32 mld_spi_slv_vector_transmit_receive_dma(struct mld_spi_slv_module *bus,
        struct mld_spi_slv_device *dev, \
        struct mld_spi_slv_async *vector)
{
    sint32 ret = 0;
    SpiSLvFaultInj_SpiSLv_BusChk_Err();
    if (!bus || !bus->bus_ops) {
        ret = -SLV_ERR_NO_BUS;
    } else if (bus->state & SPI_SLV_STATE_INITED) {
        SpiSLvFaultInj_SpiSLv_BusyChk_Err();
        if (!(bus->state & SPI_SLV_BUS_BUSY_MASK)) {
            /* async mode will check and clean it */
            if (vector->ptxdata.val)
                bus->state |= SPI_SLV_STATE_BUSY_TX | SPI_SLV_STATE_DMA_TX;

            if (vector->prxdata.val)
                bus->state |= SPI_SLV_STATE_BUSY_RX | SPI_SLV_STATE_DMA_RX;

            vector->expect_len =  0;
            ret = bus->bus_ops->spi_slv_vector_transmit_receive_dma(bus, dev, vector);

            if (ret < 0) {
                bus->state &= (uint32)(~(SPI_SLV_BUS_BUSY_MASK | SPI_SLV_BUS_BUSY_DMA_MASK | SPI_SLV_STATE_EXT_FLAGS));
                bus->bus_ops->spi_slv_transmit_stop(bus);
                SPI_SLV_DBG("%s error: %d\n", __FUNCTION__, ret);
                ret = -SLV_ERR_LOW_LEVEL;
            }
        } else {
            SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_BUSY);
            ret = -SLV_ERR_BUSY;
        }
        SpiSLvFaultInj_SpiSLv_BusyChk_Err_end();
    } else {
        SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_NO_INIT);
        ret = -SLV_ERR_NO_INIT;
    }

    return ret;
}
/**
 * Handle SPI bus error for the MLD SPI slave module.
 *
 * This function is responsible for handling errors that occur on the SPI bus for the
 * specified MLD SPI slave module. It clears the busy status and external flags, sets
 * the error end state, stops the DMA transfer, and stops the ongoing SPI transmission
 * to reset the bus and avoid affecting the next transmission.
 *
 * @param bus Pointer to the MLD SPI slave module structure. This structure contains
 *            the state and operation pointers necessary to manage the SPI bus.
 */
static void mld_spi_slv_bus_error_handle(struct mld_spi_slv_module *bus)
{
    bus->state &= (uint32)(~SPI_SLV_BUS_BUSY_STATUS_MASK);
    bus->state &= (uint32)(~SPI_SLV_STATE_EXT_FLAGS);
    bus->state |= SPI_SLV_STATE_ERR_END;
    /*PRQA S 2813 4*/
    bus->bus_ops->spi_slv_dma_stop(bus);
    /* reset bus avoid affecting the next transmission */
    bus->bus_ops->spi_slv_transmit_stop(bus);
}
/**
 * @brief Polls the SPI slave module for transmission and reception status.
 *
 * This function polls the SPI slave module to check its current state and handles
 * any pending transactions or errors. It is typically called from an asynchronous
 * or polling context to manage the SPI slave operations.
 *
 * @param bus Pointer to the SPI slave module structure that holds the operational
 *            parameters and state of the SPI slave.
 *
 * @note This function assumes that the SPI slave module has been initialized and
 *       is in a valid state before being called.
 */
static void mld_spi_slv_polling(struct mld_spi_slv_module *bus)
{
    uint32 ret = 0;
    uint32 irq_state;
    SpiSLvFaultInj_SpiSLv_BusyChk_Err();
    if (!(bus->state & SPI_SLV_STATE_INITED)) {
        SPI_SLV_DBG("%s error not inited\n", __FUNCTION__);
        SpiSLvFaultInj_SpiSLv_BusyChk_Err_end();
        return ;
    }
    /*PRQA S 2813 1*/
    ret = bus->bus_ops->spi_slv_irq_state(bus, &irq_state);

    /* Slave Mode OverFlow or UnderFlow error */
    if (ret & SPI_SLV_BUS_FIFO_STATE_ERR_MASK) {
        mld_spi_slv_bus_error_handle(bus);
    }else{
        if (bus->state & SPI_SLV_BUS_BUSY_DMA_MASK) {
            /* nothing to do */
        }else{
            spi_slv_readwrite_remain(bus);
        }
        if (bus->state & SPI_SLV_STATE_BUSY_TX) {
            if (bus->async.tx_cur >= bus->async.expect_len) {
            /* tx except satisfy ,If you need to receive,
                just turn off the send trigger, otherwise all turn off*/
                /*PRQA S 2813 4*/
                if (bus->state & SPI_SLV_STATE_BUSY_RX){
                    bus->bus_ops->spi_slv_setup_irq_mask(bus,SPI_SLV_TX_WRITE_REQ);
                }else{
                    bus->bus_ops->spi_slv_setup_irq_mask(bus,SPI_SLV_TRASPORT_FINISH);
                }

                if (bus->async.expect_len == bus->async.len) {
                    /* vector item end check next need to transmit ? */
                    /*
                        vector end and not have others need to process
                        ,Tx Finished
                    */
                    if(0 == (SPI_SLV_STATE_IS_UNS_EN & bus->state)){

                        bus->state &= (uint32)(~SPI_SLV_STATE_DMA_TX);
                        bus->state &= (uint32)(~SPI_SLV_STATE_IRQ_TX);
                        bus->state &= (uint32)(~SPI_SLV_STATE_BUSY_TX);
                    }
                    SPI_SLV_DBG("%s bus%p tx pass\n", __FUNCTION__, bus);

                }
            }
        }
        if (bus->state & SPI_SLV_STATE_BUSY_RX) {
            /* !!! Cannot be implemented using if-else must independent to check  */
            if (bus->async.rx_cur == bus->async.expect_len) {
                /* rx except satisfy , all turn off*/
                /*PRQA S 2813 1*/
                bus->bus_ops->spi_slv_setup_irq_mask(bus,SPI_SLV_TRASPORT_FINISH);

                if (bus->async.expect_len == bus->async.len) {
                    /* vector item end check next need to transmit ? */
                    /*
                        vector end and not have others  need to process
                        ,Rx Finished
                    */
                    if(0 == (SPI_SLV_STATE_IS_UNS_EN & bus->state)){
                        bus->state &= (uint32)(~SPI_SLV_STATE_DMA_RX);
                        bus->state &= (uint32)(~SPI_SLV_STATE_IRQ_RX);
                        bus->state &= (uint32)(~SPI_SLV_STATE_BUSY_RX);
                    }
                    SPI_SLV_DBG("%s bus%p rx pass\n", __FUNCTION__, bus);
                }
            }
        }
    }
    /*PRQA S 2813 1*/
    bus->bus_ops->spi_slv_clr_irq_state(bus, irq_state);
}
/**
 * Poll the SPI bus state for the MLD SPI slave module.
 *
 * This function polls the SPI bus state and performs actions based on the current state
 * and configuration of the MLD SPI slave module. It checks for initialization, handles
 * bus errors, manages DMA and interrupt state, and updates the bus state accordingly.
 *
 * @param bus Pointer to the MLD SPI slave module structure.
 */
sint32 mld_spi_slv_async_polling(struct mld_spi_slv_module *bus)
{
    sint32 ret = -1;

    if (bus->state & SPI_SLV_STATE_INITED) {
        if (bus->state & SPI_SLV_BUS_BUSY_ASYNC_MASK)
            mld_spi_slv_polling(bus);

        if (bus->state & SPI_SLV_BUS_BUSY_ASYNC_MASK)
            ret = 1;
        else
            ret = 0;
    } else {
        ret = -SLV_ERR_NO_INIT;
        SPI_SLV_DBG("%s E:%d\n", __FUNCTION__, -SLV_ERR_NO_INIT);
    }

    return ret;
}
/**
 * Write remaining data to the SPI bus.
 *
 * @param bus Pointer to the SPI slave module instance.
 * @return The number of bytes written, or -1 on error.
 */
sint32 spi_slv_write_remain(struct mld_spi_slv_module *bus)
{
    uint32 remain;
    uint32 len = 0;

    if (!bus || !bus->bus_ops)
        return -1;

    if (!bus->async.ptxdata.val)
        return 0;

    remain = bus->async.expect_len -  bus->async.tx_cur;

    if (remain <= 0)
        return 0;

    while (remain && bus->bus_ops->spi_slv_can_write(bus)) {

        if (bus->async.width_type == SPI_SLV_DATA_WIDTH_BYTE) {
            bus->bus_ops->spi_slv_write_data(bus, *(bus->async.ptxdata.u8_ptr + bus->async.tx_cur));
        } else if (bus->async.width_type == SPI_SLV_DATA_WIDTH_HALF_WORD) {
            bus->bus_ops->spi_slv_write_data(bus, *(bus->async.ptxdata.u16_ptr + bus->async.tx_cur));
        } else {
            bus->bus_ops->spi_slv_write_data(bus, *(bus->async.ptxdata.u32_ptr + bus->async.tx_cur));
        }

        bus->async.tx_cur++;
        len++;
        remain--;
    }

    SPI_SLV_DBG("%s bus %d %d\n", __FUNCTION__, bus->idx, len);
    return len;
}
/**
 * Read remaining data from the SPI bus.
 *
 * @param bus Pointer to the SPI slave module instance.
 * @return The number of bytes read, or -1 on error.
 */
sint32 spi_slv_read_remain(struct mld_spi_slv_module *bus)
{
    uint32 remain;
    uint32 len = 0;

    if (!bus || !bus->bus_ops)
        return -1;

    if (!bus->async.prxdata.val)
        return 0;

    remain = bus->async.expect_len -  bus->async.rx_cur;

    if ( remain <= 0)
        return 0;
    while (remain && bus->bus_ops->spi_slv_can_read(bus)) {
        if (bus->async.width_type == SPI_SLV_DATA_WIDTH_BYTE) {
            *(bus->async.prxdata.u8_ptr + bus->async.rx_cur) = (uint8)bus->bus_ops->spi_slv_read_data(bus);
        } else if (bus->async.width_type == SPI_SLV_DATA_WIDTH_HALF_WORD) {
            *(bus->async.prxdata.u16_ptr + bus->async.rx_cur) = (uint16)bus->bus_ops->spi_slv_read_data(bus);
        } else {
            *(bus->async.prxdata.u32_ptr + bus->async.rx_cur) = bus->bus_ops->spi_slv_read_data(bus);
        }

        bus->async.rx_cur++;
        len++;
        remain--;
    }

    SPI_SLV_DBG("%s bus %d %d\n", __FUNCTION__, bus->idx, len);
    return len;
}
/**
 * @brief Reads and writes remaining data from/to the SPI slave module.
 *
 * This function iterates through a loop to read and write any remaining data from the
 * transmit and receive buffers of the SPI slave module. It checks if there is still
 * data to be transmitted or received, and if the SPI bus is ready to perform the
 * respective operation.
 *
 * @param bus Pointer to the SPI slave module structure.
 *
 * @note This function assumes that the `bus` pointer and its `bus_ops` member are valid.
 *       It will not perform any checks for `NULL` pointers except for the initial check
 *       on `bus` and `bus->bus_ops`.
 */
void spi_slv_readwrite_remain(struct mld_spi_slv_module *bus)
{
    uint32 ret = 0;
    uint16 dummy = 0;
    uint32 rx_remain = 0,rx_read  = 0;
    uint32 tx_remain = 0,tx_write = 0;
    uint32 irq_state;

    if (!bus || !bus->bus_ops){
        return ;
    }

    if (bus->async.prxdata.val){
        rx_remain = bus->async.expect_len -  bus->async.rx_cur;
    }
    if (bus->async.ptxdata.val){
        tx_remain = bus->async.expect_len -  bus->async.tx_cur;
    }
    while(dummy < SPI_SLV_MAX_RETRY_TIMES){
        if ( rx_remain > 0  && bus->bus_ops->spi_slv_can_read(bus)){
            if (bus->async.width_type == SPI_SLV_DATA_WIDTH_BYTE) {
                *(bus->async.prxdata.u8_ptr + bus->async.rx_cur) = (uint8)bus->bus_ops->spi_slv_read_data(bus);
            } else if (bus->async.width_type == SPI_SLV_DATA_WIDTH_HALF_WORD) {
                *(bus->async.prxdata.u16_ptr + bus->async.rx_cur) = (uint16)bus->bus_ops->spi_slv_read_data(bus);
            } else {
                *(bus->async.prxdata.u32_ptr + bus->async.rx_cur) = bus->bus_ops->spi_slv_read_data(bus);
            }
            bus->async.rx_cur++;
            rx_remain--;
            dummy = 0;
            rx_read++;
        }
        else
        {
            dummy++;
        }
        if (tx_remain > 0 && bus->bus_ops->spi_slv_can_write(bus)){
            if (bus->async.width_type == SPI_SLV_DATA_WIDTH_BYTE) {
                bus->bus_ops->spi_slv_write_data(bus, *(bus->async.ptxdata.u8_ptr + bus->async.tx_cur));
            } else if (bus->async.width_type == SPI_SLV_DATA_WIDTH_HALF_WORD) {
                bus->bus_ops->spi_slv_write_data(bus, *(bus->async.ptxdata.u16_ptr + bus->async.tx_cur));
            } else {
                bus->bus_ops->spi_slv_write_data(bus, *(bus->async.ptxdata.u32_ptr + bus->async.tx_cur));
            }

            bus->async.tx_cur++;
            tx_remain--;
            dummy = 0;
            tx_write++;
        }
        else
        {
            dummy++;
        }
        ret = bus->bus_ops->spi_slv_irq_state(bus, &irq_state);

        /* Slave Mode OverFlow or UnderFlow error */
        if (ret & SPI_SLV_BUS_FIFO_STATE_ERR_MASK) {
            return ;
        }
        (void)irq_state;
    }

    SPI_SLV_DBG("%s bus %d %d %d\n", __FUNCTION__, bus->idx,tx_write,rx_read);
}
/**
 * Poll the SPI bus state for the MLD SPI slave module.
 *
 * This function polls the SPI bus state and performs actions based on the current state
 * and configuration of the MLD SPI slave module. It checks for initialization, handles
 * bus errors, manages DMA and interrupt state, and updates the bus state accordingly.
 *
 * @param bus Pointer to the MLD SPI slave module structure.
 */
sint32 mld_spi_slv_get_length(struct mld_spi_slv_module *bus)
{
    sint32 ret = -1;

    if ((NULL_PTR != bus) && (NULL_PTR != bus->bus_ops) &&
        (bus->state & SPI_SLV_STATE_INITED))
    {
#if (ENABLE_SLAVE_MCS_TRIG == STD_ON)
        ret = (sint32)bus->async.len;
#else
        ret = (sint32)bus->bus_ops->spi_slv_transmit_length(bus);
#endif
    }

    return ret;
}
#define SPI_SLV_STOP_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"

#ifdef __cplusplus
}
#endif
